package container

import (
	"context"
	"errors"

	"gitee.com/doraemon1996/bunny/env"
	"gitee.com/doraemon1996/bunny/log"
)

var (
	ErrManagerClosed     = errors.New("manager closed")
	ErrContainerNotFound = errors.New("container not found")
	ErrInvalidService    = errors.New("use nil service instance to launch container")
	ErrContainerClosed   = errors.New("container closed")
)

const (
	Bits_NodeID   = 10 // 节点ID位数 1024个节点
	Bits_Sequence = 53 // 序列号

	Max_NodeID   = 1<<Bits_NodeID - 1   // 节点ID最大值
	Max_Sequence = 1<<Bits_Sequence - 1 // 序列号最大值

	Shift_NodeID   = Bits_Sequence // 节点ID移位
	Shift_Sequence = 0             // 序号移位

	Mask_NodeID   = Max_NodeID << Shift_NodeID     // 节点ID掩码
	Mask_Sequence = Max_Sequence << Shift_Sequence // 序号掩码
)

/*
	ContainerID二进制位分布如下:
	 		------------------------------
	fileds  | Symbol | NodeID | Sequence |
	 		------------------------------
	bytes   |   1    |   10   |    53    |
	 		------------------------------
*/

var mng Manager

func init() {
	mng = NewManager()
	mng.Init(context.Background(), env.NodeID())
	mng.Start()
	log.ExitHandlerInsert(func() {
		mng.Stop()
	})
}

// 编码容器(服务)ID
func ContainerIDEncode(nodeID, sequence uint64) (id uint64) {
	bitsNodeID := (nodeID << Shift_NodeID) & Mask_NodeID
	bitsSequence := (sequence << Shift_Sequence) & Mask_Sequence
	return bitsNodeID | bitsSequence
}

// 解码容器(服务)ID
func ContainerIDDecode(id uint64) (nodeID, sequence uint64) {
	nodeID = (id & Mask_NodeID) >> Shift_NodeID
	sequence = (id & Mask_Sequence) >> Shift_Sequence
	return
}

// 启动一个容器(服务)
//
//	name: 服务初始注册名字
//	srv: 服务实例
//	args: 服务初始化参数
func Launch(name string, srv Service, args ...any) (containerID uint64, err error) {
	return mng.Launch(name, srv, args...)
}

// 注册服务别名
func Register(containerID uint64, name string) error {
	return mng.Register(containerID, name)
}

// 关闭指定容器
func Kill(containerID uint64) {
	mng.Kill(containerID)
}

// 获取所有已注册的服务别名
func List() map[string]uint64 {
	return mng.List()
}

// 根据服务别名获取容器ID
func Query(name string) (containerID uint64, exist bool) {
	return mng.Query(name)
}

// 派发消息
func PutMessage(containerID uint64, msg Message) {
	mng.PutMessage(containerID, msg)
}
